/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simplemetrosystem.model.Element;

import simplemetrosystem.model.Element.Interface.MetroElement;
import simplemetrosystem.model.Element.Interface.Selectable;
import simplemetrosystem.model.Element.Interface.HighLightable;
import simplemetrosystem.model.Element.Interface.ElementListener;
import simplemetrosystem.model.Element.Interface.CanvasElement;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import simplemetrosystem.control.ElementFactory;
import simplemetrosystem.control.ElementManager;

/**
 *
 * @author Eric Qian
 */
public class MetroStation
        implements MetroElement, CanvasElement, HighLightable, Selectable,
        Comparable<MetroStation>, ElementListener {

    /**
     * 
     * @param name
     * @param cName
     * @param logicX
     * @param logicY
     * @param natX
     * @param natY
     * @param language 
     */
    public MetroStation(String name, String cName, int logicX, int logicY,
            double natX, double natY, boolean language) {
        init(name, cName, logicX, logicY, natX, natY, language);
    }

    private void init(String name, String cName, int logicX, int logicY,
            double natX, double natY, boolean language) {
        this.name = name;
        this.cName = cName;

        this.logX = logicX;
        this.logY = logicY;
        this.natX = natX;
        this.natY = natY;

        this.language = language;
        this.highLightFlag = false;
        this.selectedFlag = false;
        this.shadowFlag = false;
        this.shaX = 0;
        this.shaY = 0;

        eUpdate();
    }

    /**
     * 
     * @return
     */
    public int getLogX() {
        return logX;
    }

    /**
     * 
     * @return
     */
    public int getLogY() {
        return logY;
    }

    /**
     * 
     * @return
     */
    public String getName() {
        return name;
    }

    public String getChineseName() {
        return cName;
    }

    public String getDisplayName() {
        if (language) {
            return getName();
        } else {
            return getChineseName();
        }
    }

    /**
     * 
     * @return
     */
    public double getNatX() {
        return natX;
    }

    /**
     * 
     * @return
     */
    public double getNatY() {
        return natY;
    }

    /**
     * 
     * @param logX
     */
    public void setLogX(int logX) {
        this.logX = logX;
    }

    /**
     * 
     * @param logY
     */
    public void setLogY(int logY) {
        this.logY = logY;
    }

    public int getHeight() {
        return 2;
    }

    public int getWidth() {
        return lines.size() > 1 ? 4 : 2;
    }

    /**
     * 
     * @return
     */
    public int getLinesSize() {
        return lines.size();
    }

    /**
     * 
     * @param i
     * @return
     */
    public MetroLine getLineAt(int i) {
        return lines.get(i);
    }

    /**
     * 
     * @return
     */
    public int getEdgesSize() {
        return edges.size();
    }

    /**
     * 
     * @param i
     * @return
     */
    public MetroEdge getEdgeAt(int i) {
        return edges.get(i);
    }

    public MetroEdge[] getEdgesOfLine(MetroLine line) {
        MetroEdge[] aEdges = new MetroEdge[getEdgeOfLineSize(line)];
        int j = 0;
        for (int i = 0; i < edges.size(); i++) {
            if (edges.get(i).getLine() == line) {
                aEdges[j++] = edges.get(i);
            }
        }
        return aEdges;
    }

    public int getEdgeOfLineSize(MetroLine line) {
        int size = 0;
        for (int i = 0; i < edges.size(); i++) {
            if (edges.get(i).getLine() == line) {
                size++;
            }
        }
        return size;
    }

    /**
     * 
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 
     * @param cName
     */
    public void setChineseName(String cName) {
        this.cName = cName;
    }

    /**
     * 
     * @param natX
     */
    public void setNatX(double natX) {
        this.natX = natX;
    }

    /**
     * 
     * @param natY
     */
    public void setNatY(double natY) {
        this.natY = natY;
    }

    /**
     * 
     * @param doc
     * @return
     */
    public Element getElement(Document doc) {
        Element lineElement = doc.createElement(ElementFactory.ROOT_STATION);

        Element nameElement = doc.createElement(ElementFactory.STAT_NAM);
        lineElement.appendChild(nameElement);
        Text nameText = doc.createTextNode(name);
        nameElement.appendChild(nameText);

        Element cNameElement = doc.createElement(ElementFactory.STAT_CNAM);
        lineElement.appendChild(cNameElement);
        Text cNameText = doc.createTextNode(cName);
        cNameElement.appendChild(cNameText);

        Element logXElement = doc.createElement(ElementFactory.STAT_LOGX);
        lineElement.appendChild(logXElement);
        Text logXText = doc.createTextNode("" + logX);
        logXElement.appendChild(logXText);

        Element logYElement = doc.createElement(ElementFactory.STAT_LOGY);
        lineElement.appendChild(logYElement);
        Text logYText = doc.createTextNode("" + logY);
        logYElement.appendChild(logYText);

        Element natXElement = doc.createElement(ElementFactory.STAT_NATX);
        lineElement.appendChild(natXElement);
        Text natXText = doc.createTextNode("" + natX);
        natXElement.appendChild(natXText);

        Element natYElement = doc.createElement(ElementFactory.STAT_NATY);
        lineElement.appendChild(natYElement);
        Text natYText = doc.createTextNode("" + natY);
        natYElement.appendChild(natYText);

        return lineElement;
    }

    @Override
    public String toString() {
        return "<station>" + "\n" +
                "<name>" + name + "</name>" + "\n" +
                "<cName>" + cName + "</name>" + "\n" +
                "<logX>" + logX + "</logX>" + "\n" +
                "<logY>" + logY + "</logY>" + "\n" +
                "<natX>" + natX + "</natX>" + "\n" +
                "<natY>" + natY + "</natY>" + "\n" +
                "</station>" + "\n";
    }

    public int compareTo(MetroStation o) {
        if (name.compareTo(o.name) < 0) {
            return -1;
        } else if (name.compareTo(o.name) > 0) {
            return 1;
        } else {
            return 0;
        }
    }

    public void eUpdate() {
        ElementManager elementManager = ElementManager.getInstance();
        lines = elementManager.getLinesOfStation(this);
        Collections.sort(lines);
        edges = elementManager.getEdgesOfStation(this);
        Collections.sort(edges);
    }

    public void draw(Graphics2D gg, int matrixSize) {
        int width = getWidth();
        int height = getHeight();

        Graphics2D g2D = (Graphics2D) gg.create();

        int strokeWidth = matrixSize / 10 > 1 ? matrixSize / 10 : 2;
        g2D.setStroke(new BasicStroke(strokeWidth));

        RoundRectangle2D r = new RoundRectangle2D.Double(matrixSize * logX,
                matrixSize * logY, matrixSize * width, matrixSize * height,
                matrixSize * width / 4, matrixSize * height / 4);

        g2D.setColor(Color.WHITE);
        g2D.fill(r);
        g2D.setColor(Color.BLACK);
        g2D.draw(r);
    }

    public void drawSelected(Graphics2D g2D, int matrixSize) {
        int width = getWidth();
        int height = getHeight();

        int strokeWidth = matrixSize / 10 > 1 ? matrixSize / 10 : 2;
        g2D.setStroke(new BasicStroke(strokeWidth));

        RoundRectangle2D r = new RoundRectangle2D.Double(matrixSize * logX - matrixSize / 10,
                matrixSize * logY - matrixSize / 10, matrixSize * width + matrixSize / 5,
                matrixSize * height + matrixSize / 5, matrixSize * width / 4 + matrixSize / 10,
                matrixSize * height / 4 + matrixSize / 10);

        g2D.setColor(Color.BLUE);
        g2D.draw(r);
    }

    public void drawShadow(Graphics2D g2D, int matrixSize) {
        int width = getWidth();
        int height = getHeight();

        int strokeWidth = matrixSize / 10 > 2 ? matrixSize / 10 : 2;
        g2D.setStroke(new BasicStroke(strokeWidth));

        RoundRectangle2D r = new RoundRectangle2D.Double(matrixSize * logX + shaX,
                matrixSize * logY + shaY, matrixSize * width, matrixSize * height,
                matrixSize * width / 4, matrixSize * height / 4);

        g2D.setColor(Color.DARK_GRAY);
        g2D.draw(r);
    }

    public void drawHighLight(Graphics2D g2D, int matrixSize) {
        int width = getWidth();
        int height = getHeight();

        int strokeWidth = matrixSize / 10 > 2 ? matrixSize / 10 : 2;
        g2D.setStroke(new BasicStroke(strokeWidth));

        RoundRectangle2D r = new RoundRectangle2D.Double(matrixSize * logX - matrixSize / 10,
                matrixSize * logY - matrixSize / 10, matrixSize * width + matrixSize / 5,
                matrixSize * height + matrixSize / 5, matrixSize * width / 4 + matrixSize / 10,
                matrixSize * height / 4 + matrixSize / 10);

        g2D.setColor(Color.RED);
        g2D.draw(r);
    }

    public boolean isSelected() {
        return selectedFlag;
    }

    public boolean isHighLight() {
        return highLightFlag;
    }

    public void setSelected(boolean selectFlag) {
        this.selectedFlag = selectFlag;
    }

    public void setHighLight(boolean lightFlag) {
        this.highLightFlag = lightFlag;
    }

    public boolean isShadow() {
        return shadowFlag;
    }

    public void setShadow(boolean shadow, int x, int y) {
        this.shadowFlag = shadow;
        this.shaX = x;
        this.shaY = y;
    }
    private String name;
    private String cName;
    private int logX;
    private int logY;
    private double natX;
    private double natY;
    private ArrayList<MetroLine> lines;
    private ArrayList<MetroEdge> edges;
    private boolean language;
    private boolean selectedFlag;
    private boolean highLightFlag;
    private boolean shadowFlag;
    private int shaX;
    private int shaY;
}
